package ice.dao.util;

import ice.Constants;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;

import cube.utils.FileUtil;
import cube.utils.SQLUtil;

/**
 * MemDB
 * 
 * @author abiao
 */
public class MemDB extends DBUtil {

    /**
     * 内存库
     */
    private static MemDB memDB;

    /**
     * hideme
     */
    private MemDB() {
        initMemDB();
    }

    /**
     * 初始化内存库
     */
    public static MemDB initDB() {
        if (memDB == null) {
            memDB = new MemDB();
        }
        return memDB;
    }

    /**
     * 初始化内存数据库
     */
    private void initMemDB() {
        try {
            String[] sqlList = getSqlList();
            initMemDBTables(sqlList);
            syncDataFromEntity(sqlList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 从实体数据库同步数据到内存数据库
     */
    private void syncDataFromEntity(String[] sqlList) throws Exception {
        DBUtil db = DBUtil.getEntityDB();
        List<String> tableList = getTableList(sqlList);
        for (String tableName : tableList) {
            String selectSql = "select * from " + tableName;
            String insertSql = "insert into " + tableName + " values(";
            List<TableRow> rowList = db.queryForIndex(selectSql);
            List<Object[]> valuesList = new ArrayList<Object[]>();
            for (TableRow row : rowList) {
                Object[] insertValues = new Object[row.size()];
                for (int i = 0; i < insertValues.length; i++) {
                    insertValues[i] = row.get("" + (i + 1));
                }
                valuesList.add(insertValues);
            }
            if (!valuesList.isEmpty()) {
                int colSize = valuesList.get(0).length;
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < colSize; i++) {
                    sb.append("?, ");
                }
                insertSql += sb.substring(0, sb.length() - 2) + ")";
            }
            for (Object[] values : valuesList) {
                update(insertSql, values);
            }
        }
    }

    /**
     * 初始化内存数据库表结构
     */
    private void initMemDBTables(String[] sqlList) throws Exception {
        batchUpdate(getSqlObList(sqlList));
    }

    /**
     * 获取Table名列表
     */
    private List<String> getTableList(String[] sqlList) {
        List<String> tableList = new ArrayList<String>();
        for (String sql : sqlList) {
            int index1 = sql.indexOf("CREATE TABLE IF NOT EXISTS");
            int index2 = sql.indexOf('(');
            if (index1 >= 0 && (index2 > index1)) {
                tableList.add(sql.substring("CREATE TABLE if not exists".length() + 1, index2).trim());
            }
        }
        return tableList;
    }

    /**
     * 生成需要执行的Sql对象列表
     */
    public List<SqlObject> getSqlObList(String[] sqlList) {
        List<SqlObject> sqlObList = new ArrayList<SqlObject>();
        for (String sql : sqlList) {
            sqlObList.add(new SqlObject(sql.trim()));
        }
        return sqlObList;
    }

    /**
     * 从Sql文件中获取初始化语句列表
     */
    private String[] getSqlList() {
        String sqlText = FileUtil.readText(Constants.SQLFILE);
        String[] sqlList = sqlText.split(";");
        for (int i = 0; i < sqlList.length; i++) {
            sqlList[i] = sqlList[i].trim();
        }
        return sqlList;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<TableRow> query(String sql, Object[] params) {
        synchronized (MemDB.class) {
            return new MemQueryResult(this, sql, params).queryList();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<TableRow> queryForIndex(String sql, Object[] params) {
        return new MemQueryForIndexResult(this, sql, params).queryList();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void update(String sql, Object[] params) throws Exception {
        PreparedStatement prepStmt = getPrepStmt(sql);
        SQLUtil.setSQLParams(prepStmt, params);
        prepStmt.executeUpdate();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public synchronized void batchUpdate(List<SqlObject> sqlObList) throws Exception {
        if (sqlObList == null || sqlObList.isEmpty()) {
            return;
        }
        getConnection().setAutoCommit(false);
        for (SqlObject sqlOb : sqlObList) {
            PreparedStatement stmt = getPrepStmt(sqlOb.getSql());
            SQLUtil.setSQLParams(stmt, sqlOb.getParams());
            stmt.executeUpdate();
        }
        getConnection().commit();
        getConnection().setAutoCommit(true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Connection getConnection() throws Exception {
        return SqliteDB.getConnection();
    }
}
